package org.zgflex.desktop.selection
{
	import flash.display.DisplayObject;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	import mx.collections.ArrayCollection;
	import mx.containers.Canvas;
	
	import org.zgflex.desktop.ArrayIterator;
	import org.zgflex.desktop.IIconSelector;

	/**
	 * A base class for a selection area.<br/>
	 * Selection area draws the rectangle in the front layer of a desktop, based on dimensions sent from Desktop.
	 * @author dankok
	 * 
	 */	
	public class SelectionAreaBase implements ISelectionArea
	{
		/**
		 * Constructor 
		 * @param target
		 * 
		 */		
		public function SelectionAreaBase(target:IIconSelector = null)
		{
			if (target)
				this.target = target;
		}
		
		/**
		 * Selection area background color. 
		 */	
		public var backgroundColor:uint = 0x00ff00;
		
		/**
		 * Selection area background alpha. 
		 */	
		public var backgroundAlpha:Number = 0.5;
		
		/**
		 * Selection area border color. 
		 */	
		public var borderColor:uint = 0xffff00;
		
		/**
		 * Selection area border alpha. 
		 */	
		public var borderAlpha:Number = 0.5;
		
		/**
		 * Selection area border width. 
		 */	
		public var borderWidth:uint = 2;
		
		/**
		 * @private 
		 */
		protected var _previouslySelectedIcons:ArrayCollection = new ArrayCollection();
		
		/**
		 * @private 
		 */
		protected var _moved:Boolean = false;
		
		/**
		 * @private 
		 */
		protected var _target:IIconSelector;
		/**
		 * @inheritDoc
		 * 
		 */		
		public function set target(value:IIconSelector):void {
			_target = value;
		}
		public function get target():IIconSelector {
			if (_target == null)
				throw new Error("target not defined");
			return _target;
		}
		
		/**
		 * @private 
		 */
		protected var _surface:Canvas;
		/**
		 * @inheritDoc
		 * 
		 */	
		public function set surface(value:Canvas):void {
			_surface = value;
		}
		public function get surface():Canvas {
			if (_surface == null)
				throw new Error("surface not defined");
			return _surface;
		}
		
		/**
		 * @private 
		 */
		protected var _origin:Point;
		
		/**
		 * @inheritDoc
		 * 
		 */		
		public function start(point:Point):void
		{
			_origin = point.clone();
			
			trace("Selection start");
		}
		
		/**
		 * @inheritDoc
		 * 
		 */		
		public function move(currentPoint:Point, ctrlPressed:Boolean = false):void
		{
			if (!_moved){
				_previouslySelectedIcons.removeAll();
				var it:ArrayIterator = target.selectedIconsIterator;
				it.reset();
				var icon:DisplayObject;
				while (it.hasNext()){
					icon = it.next() as DisplayObject;
					_previouslySelectedIcons.addItem(icon);
				}
				_moved = true;
			}			
			
			var p:Point = currentPoint.clone();
			// check the borders
			if (p.x < 0)
				p.x = 0;
			if (p.y < 0)
				p.y = 0;
			if (p.x > _surface.width)
				p.x = _surface.width;
			if (p.y > _surface.height)
				p.y = _surface.height;
			
			var rect:Rectangle = new Rectangle();
			rect.topLeft = _origin;
			rect.bottomRight = p;
			
			draw(absRect(rect));
			selectIconsInRectangle(rect, ctrlPressed); 
			
			trace("Selection move");
		}
		
		/**
		 * @inheritDoc
		 * 
		 */		
		public function stop():void
		{
			_origin = null;
			trace("Selection stop");
			surface.graphics.clear();
			_moved = false;
		}
		
		/**
		 * Draws the selection rectangle 
		 * @param rect
		 * 
		 */		
		protected function draw(rect:Rectangle):void {			
			// abstract
		}
		
		/**
		 * Selects icons in a selected area 
		 * @param rect
		 * 
		 */		
		protected function selectIconsInRectangle(rect:Rectangle, ctrlPressed:Boolean):void {
			var it:ArrayIterator = target.iconsIterator;
			it.reset();
			while (it.hasNext()){
				var icon:DisplayObject = it.next() as DisplayObject;
				var iconBounds:Rectangle = icon.getBounds(surface);
				var iconCenterPoint:Point = iconBounds.topLeft.add(new Point(iconBounds.width/2, iconBounds.height/2));
				
				if (absRect(rect).containsPoint(iconCenterPoint)){
					if (ctrlPressed){
						if (_previouslySelectedIcons.contains(icon))
							target.deselectIcon(icon);
						else
							target.selectIcon(icon);
					}	
					else
						target.selectIcon(icon);
				}
				else {
					if (_previouslySelectedIcons.contains(icon))
						target.selectIcon(icon);
					else
						target.deselectIcon(icon);
				}
			}
		}
		
		/**
		 * Returns the "absolute" rectangle, with no negative width and height 
		 * @param rect
		 * @return 
		 * 
		 */		
		protected static function absRect(rect:Rectangle):Rectangle {
			var r:Rectangle = rect.clone();
			var x1:Number = r.topLeft.x;
			var x2:Number = r.bottomRight.x;
			var y1:Number = r.topLeft.y;
			var y2:Number = r.bottomRight.y;
			if (x1 > x2){				
				r.x = x2;
				r.width = x1 - x2;
			}			
			if (y1 > y2){
				r.y = y2;
				r.height = y1 - y2;
			}
			return r;
		}
	}
}